/*******************************************************************************************************
 *
 * 1 使用新API解析JSON，对解析JSON出现可能出现的异常进行了处理
 * 2 超时处理做了修改，先给isTimeout赋值，再调用abort（不采用条件status==0指定超时）
 * 3 XHR创建方式修改（勿重复检测浏览器http://www.cnblogs.com/snandy/archive/2011/05/24/2055048.html）
 * 4 增加scope参数，success可指定上下文
 * 
 * 
 *******************************************************************************************************/

/**
 * JavaScript Ajax Library v0.9
 * Copyright (c) 2010 snandy
 * Blog: http://www.cnblogs.com/snandy
 * QQ群: 34580561
 * Date: 2011-06-13
 * 
 * 1,执行基本ajax请求,返回XMLHttpRequest
 * Ajax.request(url,{
 *         async     是否异步 true(默认)
 *         method     请求方式 POST or GET(默认)
 *         type     数据格式 text(默认) or xml or json
 *         encode     请求的编码 UTF-8(默认)
 *         timeout 请求超时时间 0(默认)
 *         data     请求参数 (字符串或json)
 *         scope   成功回调执行上下文
 *         success 请求成功后响应函数 参数为text,json,xml数据
 *         failure 请求失败后响应函数 参数为xmlHttp, msg, exp
 * });
 * 
 * 2,执行ajax请求,返回纯文本
 * Ajax.text(url,{
 *         ...
 * });
 * 
 * 3,执行ajax请求,返回JSON
 * Ajax.json(url,{
 *         ...
 * });
 * 
 * 4,执行ajax请求,返回XML
 * Ajax.xml(url,{
 *         ...
 * });
 */

Ajax = function(window) {

var createXHR = window.XMLHttpRequest ?
    function() {
        try{
            return new window.XMLHttpRequest();
        }catch(e){}
    } :
    function() {
        try{
            return new window.ActiveXObject( "Microsoft.XMLHTTP" );
        }catch(e){}
    };
    
function request(url,opt) {
    function fn(){}
    opt = opt || {};
    var async   = opt.async !== false,
        method  = opt.method     || 'GET',
        type    = opt.type         || 'text',
        encode  = opt.encode     || 'UTF-8',
        timeout = opt.timeout     || 0,
        data    = opt.data,
        scope   = opt.scope,
        success = opt.success     || fn,
        failure = opt.failure     || fn;
        method  = method.toUpperCase();
        
    if(data && typeof data == 'object') {//对象转换成字符串键值对
        data = _serialize(data);
    }
    if(method == 'GET' && data) {
        url += (url.indexOf('?') == -1 ? '?' : '&') + data;
    }
    
    var xhr = createXHR();
    if(!xhr){return;}
    
    var isTimeout = false, timer;
    if(async && timeout>0) {
        timer = window.setTimeout(function() {
            isTimeout = true;// 先给isTimeout赋值，不能先调用abort
            xhr.abort();
        },timeout);
    }
    xhr.onreadystatechange = function() {
        if(xhr.readyState == 4) {
            if(isTimeout){
                failure(xhr,'request timeout');
            }else {
                _onStateChange(xhr, type, success, failure, scope);
                window.clearTimeout(timer);
            }
        }else{}
    };
    xhr.open(method,url,async);
    if(method == 'POST') {
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;charset=' + encode);
    }
    xhr.send(data);
    return xhr;
}

function _serialize(obj) {
    var a = [], key, val;
    for(key in obj) {
        val = obj[key];
        if(val.constructor == Array) {
            for(var i=0,len=val.length;i<len;i++) {
                a.push(key + '=' + encodeURIComponent(val[i]));
            }
        }else {
            a.push(key + '=' + encodeURIComponent(val));
        }
    }
    return a.join('&');
}
function _onStateChange(xhr, type, success, failure, scope) {
    var s = xhr.status, result;
    if(s>= 200 && s < 300) {
        switch(type) {
            case 'text':
                result = xhr.responseText;
                break;
            case 'json':
                // http://snandy.javaeye.com/blog/615216
                result = function(str) {
                    try{
                        return window.JSON.parse(str);
                    }catch(e){
                        try{
                            return (new Function('return ' + str))();
                        }catch(e){
                            failure(xhr,'parse json error',e);
                        }
                    }
                }(xhr.responseText);
                break;
            case 'xml':
                result = xhr.responseXML;
                break;
        }
        // text, 返回空字符时执行success
        // json, 返回空对象{}时执行suceess，但解析json失败，函数没有返回值时默认返回undefined
        result !== undefined && success.call(scope, result);
    }else {
        failure(xhr, xhr.status);
    }
    xhr = null;
}

return (function(){
    var Ajax = {request:request}, types = ['text','json','xml'];
    for(var i=0,len=types.length; i<len; i++) {
        Ajax[types[i]] = function(i) {
            return function(url,opt) {
                opt = opt || {};
                opt.type = types[i];
                return request(url, opt);
            }
        }(i);
    }
    return Ajax;
})();
}(this);